package gate

import (
	"leaf/chanrpc"
	"leaf/network"
)

type MultiClient struct {
	PendingWriteNum int
	MaxMsgLen       uint32
	Processor       network.Processor
	AgentChanRPC    *chanrpc.Server
	LenMsgLen       int
	LittleEndian    bool
	ConnectServer	interface{}
	CloseServer		interface{}
	NewAgent        interface{}
	CloseAgent      interface{}
	ChanRPCServer   *chanrpc.Server

	server  *chanrpc.Server
	items   map[string]*Client
	signals map[string]chan bool
}

const (
	ConnectServer = "ConnectServer"
	CloseServer   = "CloseServer"
)

func (client *MultiClient) OnInit() {
	client.server = client.ChanRPCServer
	client.items = make(map[string]*Client)
	client.signals = make(map[string]chan bool)
	if client.ConnectServer == nil {
		client.ConnectServer = ConnectServer
	}

	if client.CloseServer == nil {
		client.CloseServer = CloseServer
	}

	client.ChanRPCServer.Register(client.ConnectServer, func(args []interface{}) {
		address := args[0].(string)
		item := new(Client)
		item.TCPAddr = address
		item.TcpConnNum = 1
		item.PendingWriteNum = client.PendingWriteNum
		item.MaxMsgLen = client.MaxMsgLen
		item.Processor = client.Processor
		item.AgentChanRPC = client.AgentChanRPC
		item.AutoReconnect = false
		item.LenMsgLen = client.LenMsgLen
		item.LittleEndian = client.LittleEndian
		item.NewTcpAgent = client.NewAgent
		item.CloseTcpAgent = client.CloseAgent
		client.items[address] = item

		closeSignal := make(chan bool, 1)
		client.signals[address] = closeSignal

		go item.Run(closeSignal)
	})

	client.ChanRPCServer.Register(client.CloseServer, func(args []interface{}) {
		address := args[0].(string)
		closeSignal, exists := client.signals[address]
		if !exists {
			return
		}

		closeSignal <- true
		item := client.items[address]
		item.OnExit()

		delete(client.items, address)
		delete(client.signals, address)
	})
}

func (client *MultiClient) Run(closeSignal chan bool) {
	client.items = make(map[string]*Client)
	for {
		select {
		case <-closeSignal:
			client.server.Close()
			for _, exitSignal := range client.signals {
				exitSignal <- true
			}
			client.signals = nil
			for _, exitSignal := range client.signals {
				exitSignal <- true
			}
			client.signals = nil

			return
		case ci := <-client.server.ChanCall:
			client.server.Exec(ci)
		}
	}
}

func (client *MultiClient) OnExit() {
	for _, item := range client.items {
		item.OnExit()
	}
	client.items = nil
}
